package org.testis.services;

import org.testis.data.AtofModuleConstants;
import org.testis.data.TestStepDataObject;
import org.testis.data.TestStepException;
import org.testis.data.TestStepResultDataObject;
import org.testis.data.TestStepResultDataObjectDistributor;
import org.testis.data.TestStepResultType;
import org.testis.logging.AtofLogLevel;
import org.testis.logging.LogSenderService;
import org.testis.testdriver.AtofEnumaration.AtofModule;
import org.testis.threading.Task;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Each test step for a module is a task. And each module related task
 * extends AtofModuleTask. 
 * @author nurhat
 */
public abstract class AtofModuleTask extends Task {

    protected AtofModuleService m_service;
    protected TestStepResultDataObject m_result;

    /**
     * Each module task contains a dataobject and a provider m_service
     * @param dataObj
     * @param m_service
     */
    public AtofModuleTask(TestStepDataObject dataObj,
            AtofModuleService service) {
        super(dataObj.getMessageId());
        this.m_service = service;
        service.setDataObj(dataObj);
        m_result =
                new TestStepResultDataObject(dataObj);
        validataDataObj();

    }

    /**
     * Validates incoming data before execution step
     */
    public void validataDataObj() {
        String moduleType = m_service.getDataObj().getModuleType();
        if (moduleType == null) {
            throw new TestStepException(
                    TestStepResultType.MISTAKE,
                    "Module type   must not be null...");
        }
        try {
            AtofModule module = AtofModule.valueOf(moduleType);
        } catch (IllegalArgumentException ex) {

            throw new TestStepException(
                    TestStepResultType.MISTAKE,
                    "Module type   is not supported...");
        }
        String actionType = m_service.getDataObj().getActionType();
        if (actionType == null) {
            throw new TestStepException(
                    TestStepResultType.MISTAKE,
                    "Action type  of module must not be null...");
        }

    }

    /**
     * Test step running over thread with this method.
     * Module can override this method to do special things.
     */
    @Override
    public void run() {
        Exception currentException = null;
        try {
            boolean response = m_service.runTest();
            m_result.setResult(response);
            if (response) {
                m_result.setResultType(TestStepResultType.PASS);
            } else {
                m_result.setResultType(TestStepResultType.ERROR);
            }
            Thread.sleep(1000);
        } catch (TestStepException ex) {
            m_result.setResultType(ex.getResultType());
            currentException = ex;
        } catch (RuntimeException ex) {
            m_result.setResultType(TestStepResultType.FAILURE);
            currentException = ex;
        } catch (InterruptedException ex) {
            m_result.setResultType(TestStepResultType.TIMEOUT);
            currentException = ex;
        } catch (Exception ex) {
            m_result.setResultType(TestStepResultType.FAILURE);
            currentException = ex;
        }
        if (currentException != null) {
            try {
                LogSenderService.putMessageOnQueue("AtofModuleTask",
                        AtofLogLevel.ERROR,
                        currentException.getMessage(),
                        m_service.getDataObj().
                        getMessageId());
            } catch (Exception ex) {
            }
        }
    }

    /**
     * This function called after execution of task.
     * Any post-execute-action can be done and this function can be
     * overrided. e.g. sending execution results
     */
    @Override
    public void afterExecute() {
        m_result.setCancelled(
                m_cancelled);
        if (m_result.getResultType() != null) {
            m_result.getReturnValueList().put("TEST_RESULT", m_result.getResultType().name());
        }else{
            m_result.getReturnValueList().put("TEST_RESULT", TestStepResultType.NULL.name());
        }
        String postFixValue = "";
        if (m_service.getDataObj().getStoreResultPostfix() != null) {
            postFixValue = m_service.getDataObj().getStoreResultPostfix();
        }
        if (m_service.getDataObj().getDataToApply().containsKey(AtofModuleConstants.OUTPUT_KEY_POSTFIX_VAL)) {
            String tmpValue = m_service.getDataObj().getDataToApply().get(AtofModuleConstants.OUTPUT_KEY_POSTFIX_VAL);
            if (!tmpValue.isEmpty()) {
                postFixValue = tmpValue;
            }
        }
        postFixValue = postFixValue.trim();
        if (m_result.getReturnValueList().size() > 0) {
            LinkedHashMap<String, String> newReturnValueList = null;
            if (!postFixValue.isEmpty()) {
                newReturnValueList = new LinkedHashMap<String, String>();
            }
            StringBuilder sb = new StringBuilder();
            Iterator iter = m_result.getReturnValueList().entrySet().
                    iterator();
            while (iter.hasNext()) {
                Map.Entry entry = (Map.Entry) iter.next();
                if (entry.getValue() != null) {
                    sb.append(entry.getKey() + ":");
                    if (newReturnValueList != null) {
                        newReturnValueList.put(entry.getKey().toString() + postFixValue, entry.getValue().toString());
                        sb.append(" and " + entry.getKey().toString() + postFixValue + ":");
                    }
                    sb.append(entry.getValue() + "\n");
                }
            }

            LogSenderService.putMessageOnQueue(
                    "AtofModuleTask",
                    AtofLogLevel.INFO,
                    "ReturnValueList:\n" + sb.toString(),
                    m_service.getDataObj().getMessageId());
            if (newReturnValueList != null) {
                m_result.getReturnValueList().putAll(newReturnValueList);
            }
        }
        TestStepResultDataObjectDistributor.getInstance().
                distributeData(m_result);
    }
}
